`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:  X-Speed.com.cn
// Engineer: yansf
// 
// Create Date:    01/15/2024
// Design Name: 
// Module Name:    ClkAndRst 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module ClkAndRst(
	// ------------CLK INPUT
	Clk,
	// ------------CLK OUTPUT
	Clk_5ms, 
	Clk_1s, 
	//-------------RESET SOURCE
	nRst_FrWDT, 
	nRST_REQ_FrCPU,
	nRst_Button_Fr_Cpu,
	//-------------OUTPUT RST SIGNAL
	nRst_Global, 
	nRST_PORESET_toCPU, 
	//-------------RST SIGNAL OUTPUT REASON
	r_Rst_Botton_Reseted,
	r_Req_Reseted,
	r_wdt_Reseted,
	rst_reason_clr,
	//-------------POWER DOWN INT SIGNAL
	nPM_FIQ_OUT
);

input 	Clk;
input 	nRst_FrWDT; 
input 	nRST_REQ_FrCPU;
input	nRst_Button_Fr_Cpu;
input   nPM_FIQ_OUT;
input   rst_reason_clr;

output 	Clk_5ms;
output	Clk_1s;
output 	nRst_Global;
output	nRST_PORESET_toCPU;
output 	r_Rst_Botton_Reseted;
output 	r_Req_Reseted;
output	r_wdt_Reseted;

// -----------------------produce 5ms period clk----------------------
parameter NUMBER_2p5ms = 60000;	// 16'hEA60
parameter WIDTH_2p5ms = 16;
reg [WIDTH_2p5ms-1 : 0] cnt_2p5ms = 0;
reg Clk_5ms = 1'b0;
reg last_Clk_5ms = 1'b0;

// Because the CPU's Power on Sequence use Clk_5ms, and r_nRst_WDT keep 200ms so Clk_5ms don't be reseted by r_nRst_WDT
always @( posedge Clk )
begin
	if ( cnt_2p5ms == NUMBER_2p5ms )
		begin
			cnt_2p5ms <= 0;
			Clk_5ms <= ~Clk_5ms;
		end
	else
		begin
			cnt_2p5ms <= cnt_2p5ms + 1'b1;
			Clk_5ms <= Clk_5ms;
		end
end

// -----------------------produce 1s period clk----------------------
parameter NUMBER_500ms = 100;	// 2'h64
parameter WIDTH_500ms = 8;
reg [WIDTH_500ms-1 : 0] cnt_500ms = 0;
reg Clk_1s = 1'b0;

always @( posedge Clk )
begin
	last_Clk_5ms <= Clk_5ms;
end

always @( posedge Clk or negedge nRst_Global)
begin
	if (!nRst_Global)
		begin
			Clk_1s <= 1'b0;
			cnt_500ms <= 0;
		end
	else
		begin
			if ( cnt_500ms == NUMBER_500ms )
				begin
					Clk_1s <= ~Clk_1s;
					cnt_500ms <= 0;
				end
			else
				begin 
					if ( ~last_Clk_5ms & Clk_5ms )	// posedge Clk_5ms
						begin
							cnt_500ms <= cnt_500ms + 1'b1;
						end
					else
						begin
							cnt_500ms <= cnt_500ms;
							Clk_1s <= Clk_1s;
						end
				end
		end
end

//---------------POWER_OFF_FLAG, delay 1us in order to avoid shaking-------------
reg 		power_off_completed  = 1'b0;
reg			power_off_delay_flag = 1'b0;
reg			nPM_FIQ_OUT_temp1 = 1'b1;
reg			nPM_FIQ_OUT_temp2 = 1'b1;

reg [5:0] 	power_off_delay_cnt  = 6'b0;
parameter 	POWER_OFF_DELAY_NUMBER = 40;

wire		nPM_FIQ_OUT_negative;
assign		nPM_FIQ_OUT_negative = !nPM_FIQ_OUT_temp1 & nPM_FIQ_OUT_temp2;


always @( posedge Clk )
begin
	nPM_FIQ_OUT_temp1 <= nPM_FIQ_OUT;
	nPM_FIQ_OUT_temp2 <= nPM_FIQ_OUT_temp1;
end

always @( posedge Clk )
begin
	if( nPM_FIQ_OUT_negative == 1'b1 )
		begin
			power_off_delay_flag <= 1'b1;
		end
	else
		begin
			power_off_delay_flag <= power_off_delay_flag;
		end
end

always @( posedge Clk )
begin
	if( power_off_delay_cnt == POWER_OFF_DELAY_NUMBER )
		begin
			power_off_completed <= 1'b1;
		end
	else
		begin
			if( (power_off_delay_flag == 1'b1) & !nPM_FIQ_OUT_temp2 ) 
				begin
					power_off_delay_cnt <= power_off_delay_cnt + 1'b1;
				end
			else
				begin
					power_off_delay_cnt <= power_off_delay_cnt;
				end
		end
end

//--- Power On Reset
parameter 	NUMBER_20ms = 3;
reg [1:0] 	cnt_20ms = 2'b0;
parameter 	NUMBER_160ms = 5'b1_1111;
reg [4:0] 	cnt_160ms = 0;
reg			power_on_completed = 1'b0;

reg nRst_Global = 1'b0;
reg last_nRst_Global = 1'b0;
reg nRST_PORESET_toCPU = 1'b0;

// keep nRST_PORESET_toCPU for at least 160ms;
always @( posedge Clk )
begin
	last_nRst_Global <= nRst_Global;
end

always @( posedge Clk )
begin
	if ( last_nRst_Global & (~nRst_Global) || power_on_completed == 1'b0 )	// posedge of nRst_Global
		begin
			cnt_160ms <= 0;
			nRST_PORESET_toCPU <= 1'b0;
		end
	else 
		if (cnt_160ms == NUMBER_160ms)
			begin
				nRST_PORESET_toCPU <= nRst_Global;		// after 160ms, released nRST_PORESET_toCPU
			end
		else
			begin
				if ( ~last_Clk_5ms & Clk_5ms )
					begin
						cnt_160ms <= cnt_160ms + 1'b1;
						nRST_PORESET_toCPU <= 1'b0;				// nRST_PORESET_toCPU at least 160ms	
					end
				else
					begin
						cnt_160ms <= cnt_160ms;
					end
			end
end

// ----------- Global_nRst Reset CPU and part of FPGA's Reg----------------
reg r_nRst_WDT = 1'b1;
reg r_nRst_REQ = 1'b1;
reg r_nRst_Button = 1'b1;

always @( posedge Clk )
begin
	r_nRst_REQ <= nRST_REQ_FrCPU;
end

always @( posedge Clk_5ms )//in order to satisfy the mr pulse width of watchdog,use Clk_5ms to synchronize
begin
	r_nRst_WDT <= nRst_FrWDT;
end

always @( posedge Clk_5ms )
begin
	r_nRst_Button <= nRst_Button_Fr_Cpu;
end

//--------------AFTER nPM_FIQ_OUT goes high,delay 20ms distinguish power on completed-----------------------
always @( posedge Clk )
begin
	if ( cnt_20ms == NUMBER_20ms )	
		begin
			power_on_completed <= 1'b1;
		end
	else
		begin
			if ( ~last_Clk_5ms & Clk_5ms )	// posedge Clk_5ms and the nPM_FIQ_OUT status is high
				begin
					cnt_20ms <= cnt_20ms + 1'b1;
				end
			else
				begin
					cnt_20ms <= cnt_20ms;
				end
		end			
end

//--------------   define global RESET in different states-----------------------------
always @( posedge Clk )
begin
	if ( power_on_completed == 1'b0 )// power on not completed,reset is low
		begin
			nRst_Global <= 1'b0;
		end
	else if (  power_on_completed == 1'b1 )	// power on Completed and power not down
			begin
				nRst_Global <= r_nRst_REQ & r_nRst_WDT ;
			end
		else
			begin
				nRst_Global <= nRst_Global; //power off, keep status
			end
end


//-----------output the RESET reason,record in registers---------------
reg r_Rst_Botton_Reseted = 1'b0;
reg	r_Req_Reseted = 1'b0;
reg	r_wdt_Reseted = 1'b0;

reg r_nRst_WDT_temp1 = 1'b1;
reg r_nRst_WDT_temp2 = 1'b1;
reg r_nRst_REQ_temp1 = 1'b1;
reg r_nRst_REQ_temp2 = 1'b1;
reg r_nRst_Button_temp1 = 1'b1;
reg r_nRst_Button_temp2 = 1'b1;

wire w_nRst_WDT_negative;
wire w_nRst_REQ_negative;
wire w_nRst_Button_negative;

assign w_nRst_WDT_negative = !r_nRst_WDT_temp1 & r_nRst_WDT_temp2;
assign w_nRst_REQ_negative = !r_nRst_REQ_temp1 & r_nRst_REQ_temp2;
assign w_nRst_Button_negative = !r_nRst_Button_temp1 & r_nRst_Button_temp2;


always @( posedge Clk )
begin
	r_nRst_Button_temp1 <= r_nRst_Button;
	r_nRst_Button_temp2 <= r_nRst_Button_temp1;
end

always @( posedge Clk )
begin
	r_nRst_REQ_temp1 <= r_nRst_REQ;
	r_nRst_REQ_temp2 <= r_nRst_REQ_temp1;
end

always @( posedge Clk )
begin
	r_nRst_WDT_temp1 <= r_nRst_WDT;
	r_nRst_WDT_temp2 <= r_nRst_WDT_temp1;
end


always @( posedge Clk )
begin
	if ( power_on_completed == 1'b0 || rst_reason_clr )//power on not completed or clr is valid,reset is low
		begin
			r_Rst_Botton_Reseted <= 1'b0;
		end
	else if ( ( power_on_completed == 1'b1) & ( power_off_completed == 1'b0 ) & w_nRst_Button_negative)	// power on Completed and power not down
			begin
				r_Rst_Botton_Reseted <= 1'b1;
			end
		else
			begin
				r_Rst_Botton_Reseted <= r_Rst_Botton_Reseted; //power off or not trigger reset, keep status
			end
end

always @( posedge Clk )
begin
	if ( power_on_completed == 1'b0 || rst_reason_clr )//power on not completed or clr is valid,reset is low
		begin
			r_Req_Reseted <= 1'b0;
		end
	else if ( ( power_on_completed == 1'b1) & ( power_off_completed == 1'b0 ) & w_nRst_REQ_negative)	// power on Completed and power not down
			begin
				r_Req_Reseted <= 1'b1;
			end
		else
			begin
				r_Req_Reseted <= r_Req_Reseted; //power off or not trigger reset, keep status
			end
end

always @( posedge Clk )
begin
	if ( power_on_completed == 1'b0 || rst_reason_clr )//power on not completed or clr is valid,reset is low
		begin
			r_wdt_Reseted <= 1'b0;
		end
	else if ( ( power_on_completed == 1'b1) & ( power_off_completed == 1'b0 ) & w_nRst_WDT_negative)	// power on Completed and power not down
			begin
				r_wdt_Reseted <= 1'b1;
			end
		else
			begin
				r_wdt_Reseted <= r_wdt_Reseted; //power off or not trigger reset, keep status
			end
end

endmodule